package jm.demo.proxy.cglib.wrapper;

import java.lang.reflect.Method;
import java.util.Arrays;

import jm.demo.auth.domain.User;
import jm.demo.proxy.cglib.wrapper.impl.UserServiceImpl;
import net.sf.cglib.beans.BeanMap;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class RoundRobinWrapper {

	@SuppressWarnings("unchecked")
	public static <S,W> W createWrapper(final RoundRobinFactory<S> source, final Class<W> wrapperClass) {

	    Enhancer enhancer = new Enhancer();
	    enhancer.setSuperclass(wrapperClass);
	    enhancer.setInterfaces(wrapperClass.getInterfaces());
	    enhancer.setCallback(new MethodInterceptor() {

	        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

	            if ("getObject".equals(method.getName())) {
	                return source.getObject();
	            }

	            if (Arrays.asList(wrapperClass.getDeclaredMethods()).contains(method)) {
	            	S object = source.getObject();
	                return method.invoke(object, args);
	            }

	            return methodProxy.invoke(source, args);
	        }
	    });

	    return (W) enhancer.create();
	}
	
	public static void main(String[] args) {
		RoundRobinFactory<IUserService> factory = new RoundRobinFactory<IUserService>();
		UserServiceImpl user_service_1 = new UserServiceImpl();
		user_service_1.setShard("aa");
		UserServiceImpl user_service_2 = new UserServiceImpl();
		user_service_2.setShard("bb");
		UserServiceImpl user_service_3 = new UserServiceImpl();
		user_service_3.setShard("cc");
		
		factory.setPool(new IUserService[] {user_service_1, user_service_2, user_service_3});
		
		IUserService wrapper = createWrapper(factory, UserServiceImpl.class);
		User user = wrapper.findUserById(1);
		System.out.println(user.getName());
		user = wrapper.findUserById(2);
		System.out.println(user.getName());
		user = wrapper.findUserById(1);
		System.out.println(user.getName());
		user = wrapper.findUserById(2);
		System.out.println(user.getName());
		user = wrapper.findUserById(2);
		System.out.println(user.getName());
		user = wrapper.findUserById(1);
		System.out.println(user.getName());
		
		try {
			Object object = (BeanMap.create(wrapper)).get("shard");
			Method[] methods = wrapper.getClass().getMethods();
			for (int i = 0; i < methods.length; i++) {
				System.out.println(methods[i].getName());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
}
